﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using SilverlightUtils;

namespace Waaahsabi.Controls
{
	public class ZoomControl : ContentControl
	{
		private Button _btnReset;
		private Point _clickPoint;
		private Point _currentOffset;
		private bool _isDragging;

		private MatrixTransform _transform;
		private Grid _xForm;
		private double _zoom;

		public ZoomControl()
		{
			DefaultStyleKey = typeof (ZoomControl);
			_zoom = InitialZoom;
		}

		public double MinZoom { get; set; }
		public double MaxZoom { get; set; }
		public double ZoomStep { get; set; }
		public double InitialZoom { get; set; }

		public double Zoom
		{
			get { return _transform.Matrix.M11; //m11 and m22 are always the same value
			}
		}

		public bool ZoomEnabled { get; set; }
		public bool PanEnabled { get; set; }

		public override void OnApplyTemplate()
		{
			_xForm = GetTemplateChild("transformationGrid") as Grid;
			if (_xForm == null)
				throw new Exception("Error fetching template element 'transformationGrid'.");
			if (_xForm.RenderTransform is MatrixTransform)
				_transform = (_xForm.RenderTransform as MatrixTransform);
			if (InitialZoom < MinZoom) InitialZoom = MinZoom;
			_transform.Matrix = new Matrix(InitialZoom, 0, 0, InitialZoom, 0, 0);
			_btnReset = GetTemplateChild("btnReset") as Button;
			if (_btnReset != null)
			{
				_btnReset.Click += delegate { _transform.Matrix = new Matrix(1, 0, 0, 1, 0, 0); };
			}
			base.OnApplyTemplate();
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			if (!PanEnabled) return;
			_isDragging = true;
			e.Handled = true;
			_clickPoint = e.GetPosition(null);
			_currentOffset = new Point(_transform.Matrix.OffsetX, _transform.Matrix.OffsetY);
			base.OnMouseLeftButtonDown(e);
		}

		protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
		{
			if (!PanEnabled) return;
			_isDragging = false;
			base.OnMouseLeftButtonUp(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			if (!_isDragging || !PanEnabled)
				return;

			Point newPoint = e.GetPosition(null);
			Point delta = _clickPoint.Subtract(newPoint);
			Matrix updatedXform = new Matrix(
				_transform.Matrix.M11, _transform.Matrix.M12, _transform.Matrix.M21, _transform.Matrix.M22,
				_currentOffset.X - delta.X, _currentOffset.Y - delta.Y
				);
			_transform.Matrix = updatedXform;
			base.OnMouseMove(e);
		}

		//zoom: m11, m22
		protected override void OnMouseWheel(MouseWheelEventArgs e)
		{
			if (!ZoomEnabled) return;
			if (e.Delta > 0)
				_zoom += ZoomStep;
			else
				_zoom -= ZoomStep;
			if (_zoom > MaxZoom)
				_zoom = MaxZoom;
			if (_zoom < MinZoom)
				_zoom = MinZoom;
			Point mousePos = e.GetPosition(this);
			MatrixTransform relativeTransform = (MatrixTransform) _xForm.TransformToVisual(this);
			double deltaX = mousePos.X - relativeTransform.Matrix.OffsetX;
			double deltaY = mousePos.Y - relativeTransform.Matrix.OffsetY;
			double m11 = _zoom;
			double m22 = _zoom;
			double offsetX = _transform.Matrix.OffsetX + deltaX*(1 - _zoom/_transform.Matrix.M11);
			double offsetY = _transform.Matrix.OffsetY + deltaY*(1 - _zoom/_transform.Matrix.M22);
			Matrix updatedXform = new Matrix(m11, _transform.Matrix.M12, _transform.Matrix.M21, m22, offsetX, offsetY);
			_transform.Matrix = updatedXform;
			base.OnMouseWheel(e);
		}
	}
}